#include "WorldChat.hpp"
#define BUF_SIZE 1024
#define FD_SIZE 1000
#define EPOLLEVENTS 1000
#define LISTENQ 10
using namespace std;

//分割字符串
void SplitString(string str, const char splitChar, list<string>& outArr);

bool running=true;

int main(int argc, char const *argv[])
{
    epoll_main();
    return 0;
}


int epoll_main()
{ 
    pthread_t t_broadcast;
    pthread_create(&t_broadcast, nullptr, t_Broadcast, nullptr);
    /* code */
    int servfd = sock_init(7687);
    do_epoll(servfd);
    close(servfd);
    running=false;
    return 0;
}

int sock_init(int port)
{
    int listenfd = -1;
    sockaddr_in servaddr;
    listenfd = socket(AF_INET, SOCK_STREAM, 0);
    if (listenfd == -1)
    {
        cout << "Listen error!" << endl
             << "Errno: " << errno << " , "
             << strerror(errno);
        exit(0);
    }
    else
    {
        cout << "Listen success!\n";
    }
    bzero(&servaddr, sizeof(servaddr));
    servaddr.sin_addr.s_addr = INADDR_ANY;
    servaddr.sin_family = AF_INET;
    servaddr.sin_port = htons(port);
    if (bind(listenfd, (sockaddr *)&servaddr, sizeof(servaddr)) == -1)
    {
        cout << "Bind error!" << endl
             << "Errno: " << errno << ", "
             << strerror(errno) << endl;
        exit(0);
    }
    else
    {
        cout << "Bind success!\n";
    }
    if (listen(listenfd, LISTENQ) == -1)
    {
        cout << "Listen error!" << endl
             << "Errno: " << errno << ", "
             << strerror(errno) << endl;
        exit(-1);
    }
    else
    {
        cout << "Listening......\n";
    }
    return listenfd;
}

void handle_event(int epollfd, epoll_event *events, int num, int listenfd, char *buf)
{
    int fd;
    for (int i = 0; i < num; i++)
    {
        /* code */
        fd = events[i].data.fd;
        if ((fd == listenfd) && (events[i].events & EPOLLIN))
        {
            cout << "Accepting client ..." << endl;
            handle_accept(epollfd, listenfd);
        }
        else if (events[i].events & EPOLLIN)
        {
            cout << "Reading from client ..." << endl;
            do_read(epollfd, fd, buf);
        }
        else if (events[i].events & EPOLLOUT)
        {
            //发送字符串
            string send;
            //登录检查
            if(!m_players[fd].isLogined){
                do_write(epollfd,fd,"Please Login Frist");                
            }            
            //指令检查
            else if (isCommand(buf))
            {
                cout<<"Command:"<<buf<<endl;
                DealCommand(fd, buf);
                modi_event(epollfd, fd, EPOLLIN);
            }
            else
            {
                cout<<"Addmsg:"<<buf<<endl;
                //加入消息队列
                std::string sender=m_players[fd].Name()+" ("+m_players[fd].Account()+") :";
                send=sender+buf;
                AddMsg(send);
                modi_event(epollfd, fd, EPOLLIN);
            }
        }
    }
}

void handle_accept(int epollfd, int listenfd)
{
    int clntfd;
    sockaddr_in clntaddr;
    socklen_t clntSZ = sizeof(clntaddr);
    clntfd = accept(listenfd, (sockaddr *)&clntaddr, &clntSZ);
    if (clntfd == -1)
    {
        cout << "Accept error!" << endl
             << "Errno: " << errno << " , "
             << strerror(errno);
        return;
    }
    else
    {
        cout << "Accept success!\n";
        cout << "Client IP: " << inet_ntoa(clntaddr.sin_addr) << ":" << clntaddr.sin_port << endl;
        AddPlayer(clntfd,clntaddr);
        add_event(epollfd, clntfd, EPOLLIN);
    }
}

void do_read(int epollfd, int fd, char *buf)
{
    int readNum = 0;
    readNum = read(fd, buf, BUF_SIZE);
    if (readNum <= 0)
    {
        close(fd);
        del_event(epollfd, fd, EPOLLIN);
    }
    else
    {
        buf[readNum] = 0;
        modi_event(epollfd, fd, EPOLLOUT);
    }
}

void do_write(int epollfd, int fd, char *buf)
{
    int writeNum = 0;
    writeNum = write(fd, buf, strlen(buf));
    if (writeNum == -1)
    {
        close(fd);
        del_event(epollfd, fd, EPOLLOUT);
    }
    else
    {
        modi_event(epollfd, fd, EPOLLIN);
    }
    memset(buf, 0, BUF_SIZE);
}

void add_event(int epollfd, int fd, int state)
{
    epoll_event ev;
    ev.data.fd = fd;
    ev.events = state;
    epoll_ctl(epollfd, EPOLL_CTL_ADD, fd, &ev);
}

void modi_event(int epollfd, int fd, int state)
{
    epoll_event ev;
    ev.data.fd = fd;
    ev.events = state;
    epoll_ctl(epollfd, EPOLL_CTL_MOD, fd, &ev);
}

void del_event(int epollfd, int fd, int state)
{
    epoll_event ev;
    ev.data.fd = fd;
    ev.events = state;
    epoll_ctl(epollfd, EPOLL_CTL_DEL, fd, &ev);
    DelPlayer(fd);
}

void do_epoll(int listenfd)
{
    int epollfd;
    epoll_event events[EPOLLEVENTS];
    epollfd = epoll_create(FD_SIZE);
    char buf[BUF_SIZE];
    memset(buf, 0, BUF_SIZE);
    int sigNum;
    add_event(epollfd, listenfd, EPOLLIN);
    cout << "Server is running ......" << endl;
    while (1)
    {
        sigNum = epoll_wait(epollfd, events, EPOLLEVENTS, -1);
        handle_event(epollfd, events, sigNum, listenfd, buf);
    }
    close(epollfd);
}

pthread_mutex_t clntLock; //信息锁

// 处理指令
void DealCommand(int sock_fd, std::string command)
{
    list<string> content; //指令信息
    //存在请求登录的指令
    if (command.find("LoginCommand::->") != -1)
    {
        SplitString(command, split_char, content);
        content.pop_front();              //指令内容退出
        string account = content.front(); //保存账号
        content.pop_front();              //账号内容退出
        string name = content.front();    //保存昵称
        content.pop_front();              //昵称内容退出

        if(m_players[sock_fd].isLogined){
            return;
        }
        m_players[sock_fd].Login(name, account);        
        AddOnlineStateMsg(sock_fd,true);
    }
}

void AddPlayer(int sockFd, sockaddr_in clntAddr)
{
    pthread_mutex_lock(&clntLock);

    //仅初始化数据，无玩家信息
    Player newPlayer = Player(sockFd, clntAddr);
    m_players.insert(M_Player::value_type(sockFd,newPlayer));

    pthread_mutex_unlock(&clntLock);
}

void DelPlayer(int sockFd){
    AddOnlineStateMsg(sockFd,false);

    pthread_mutex_lock(&clntLock);

    m_players[sockFd].isLogined=false;
    m_players.erase(sockFd); 
    pthread_mutex_unlock(&clntLock);
}
void AddOnlineStateMsg(int sock_fd,bool isOnline){
    string m=m_players[sock_fd].Name()+" ("+m_players[sock_fd].Account()+") ";
    if (isOnline)
    {
        m+="is Online";
    }else
    {
        m+="is Offline";
    }
    cout<<"上线状态播报："<<m<<endl;
    AddMsg(m);  
    
}

void Broadcast(std::string msg)
{
    pthread_mutex_lock(&clntLock);
    string forSend;
    M_Player players(m_players);
    pthread_mutex_unlock(&clntLock);
    /* code */
    for (M_Player::iterator item = players.begin(); item != players.end(); item++)
    {
        //玩家未进行登录直接跳过
        if(!item->second.isLogined){
            continue;
        }
        int writeNum = write(item->first, msg.c_str(), msg.length());
        if (writeNum == -1)
        {
            DelPlayer(item->first);
            close(item->first);
            
        }

    }
}

void* t_Broadcast(void *args)
{
    while (running)
    {
        //有消息
        if (!q_messages.empty())
        {
            Broadcast(q_messages.front());
            //发送完毕
            q_messages.pop();
        }
    }
}

bool isCommand(std::string msg)
{
    //登录指令前缀信息
    if (msg.find("LoginCommand::->") != msg.npos)
    {
        //分割符数量大于等于2
        if (msg.find_first_of('`') != msg.find_last_of('`'))
        {
            return true;
        }
        return false;
    }
    return false;
}

void AddMsg(std::string newMessage)
{
    pthread_mutex_lock(&clntLock);
    q_messages.push(newMessage);
    pthread_mutex_unlock(&clntLock);
}

void SplitString(string str, const char splitChar, list<string>& outArr)
{
    int pos = str.find(splitChar);
    while (pos != str.npos)
    {
        outArr.push_back(str.substr(0, pos));
        pos++;
        str = str.substr(pos, str.size() - 1);
        pos = str.find(splitChar);
    }
    outArr.push_back(str);
}